﻿//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//    Crolengi, this program (a part of program) is gameengine based on C++\Directx
//    Copyright (C) 2008 Pashinin Anton Alekseevich (Crol)
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.
//    (INCLUDING NEGLIGENCE OR OTHERWISE) 
//    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
//    EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//    Contacts: 
//    Mail: crolengi@gmail.com
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


#pragma once
#ifndef  Effect_Manager_h
#define  Effect_Manager_h

#include "include\\Utils\\Console.h"
#include "include\\Utils\\Timer.h"
#include "..\\import\\CRLEngi_strings_lib\\CRLEngi_strings.h"
#include "..\\import\\param_trees_lib\\param_trees.h"
#include "include\\Objects\\light.h"
#include "include\\Managers\\Camera_Manager.h"
#include "include\\Objects\\CCamera.h"

//#################################################################################################################
///// 
/////   :: КЛАСС МЕНЕДЖЕРА ЭФФЕКТОВ ::
///// 
//#################################################################################################################
class CLREngi_Effect_Manager{
protected:
	typedef struct NODE_TYP{       // структура нашего растения %)
		unsigned int     id; 		// Идентификатор
		CRLEngi_string   Name;
		ID3DXEffect     *Effect;
		DynamicRow      *Properties;
		NODE_TYP        *next;                       // Указатель на следующий  узел списка
		NODE_TYP        *prev;                       // Указатель на предыдущий узел списка
	   }NODE,*NODE_PTR;
public:
LPDIRECT3DDEVICE9       g_pd3dDevice;   // Our rendering device
unsigned int            LOADED_Effects; // число эффектов
NODE_PTR                head;           // начало списка эффектов
D3DXMATRIXA16          *matWorld;       // копия мировой 

CLREngi_Console        *Console;
CLREngi_Camera_Manager *Camera_Manager;
//#################################################################################################################
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///// Чтение параметров из структуры
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	bool          LoadFromRow(char *file){
		CRLEngi_string a;
		a = file;
		DynamicRow row;
		row.iLoadFromFile(a);
		//a = "[i] Loading lights from ";
		//a += file;
		//a += " ...";
		//Console->AddText(a,2); 
		LoadFromRow(&row);
		CRLEngi_string message;
		message = "[!] Effect Manager setup completed with ";
		message += (int)LOADED_Effects;
		message += " Effects.";		
		Console->AddText(message,3); 
		return true;	
	}
	void          LoadFromRow(DynamicRow   *row){

		// подготовка к анализу структуры
		int id1 = 0, count,id2 = 0;
		CRLEngi_string EffectName;
		EffectName = "";
		id1 = (*row).iLookId("_EFFECTS_");
        count =  (*row).iCountKnots(id1) + (*row).iCountParams(id1);
		if (id1>0)
			if (count>0){
			   id2     = (*row).TopId(id1);
			   EffectName = (*row).iLookName(id2);
               CreateNewEffect(EffectName,row);
			   for (int i=1;i<count;i++){
				   id2     = (*row).NextId(id2);
				   EffectName = (*row).iLookName(id2);
                   CreateNewEffect(EffectName,row);
			     }//for
			   }//if
	}//void

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///// Загрузка параметров из файла эффекта
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	void LoadEffectProperties(NODE_PTR to,CRLEngi_string Name){
      DynamicRow   EffRow;	  
	  EffRow.fresh();
	  if (Name!="none")
	  EffRow.iLoadFromFile(Name);
	  to->Properties = &EffRow;	
	}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///// Добавление эффекта
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    unsigned int  CreateNewEffect(CRLEngi_string EffectName,DynamicRow   *row){

		    // Вставка узла в конец списка
			NODE_PTR new_node = NULL;
			NODE_PTR curr;

			if (head == NULL) //Список пуст
				 curr = NULL; //(*head);
			else
			     curr = (head);

			// Создание нового узла
			// В C++ здесь используется оператор new
			new_node = (NODE_PTR)malloc(sizeof(NODE));
			//Заполняем поля
			LOADED_Effects      += 1;

			//(new_node->Effect) = new ID3DXEffect();
            
			int id1,id2;
			CRLEngi_string File;
			id1 = row->iLookId(EffectName);
			id2 = row->iLookInFor(id1,"_FILE_FX_");
			id2     = (*row).TopId(id2);
			File  = (row->iLookName(id2));
			
			if(FAILED(D3DXCreateEffectFromFile(g_pd3dDevice, File.getChars(), NULL, NULL, 0, NULL, &(new_node->Effect), NULL)))
			{
				Console->AddText(File.getChars(),1);
				return 0 ;
			}

			id2 = row->iLookInFor(id1,"_FILE_");
			id2     = (*row).TopId(id2);			
			File  = (row->iLookName(id2));
			LoadEffectProperties(new_node,File);

			CRLEngi_string buffer;
			buffer = "[+] Effect:  ";
			buffer += EffectName.getChars();
			Console->AddText(buffer,0);
			
			//new_node->Parameters = row;
			new_node->id         = LOADED_Effects;
			new_node->Name       = EffectName;
			new_node->next       = NULL; // Лучше это делать всегда;
			// в данном случае наш узел будет
			// последним в списке, так что это
			// просто необходимо
			// Поиск конца списка и вставка
			if (curr == NULL){ //Список пуст
				(head) = new_node;
				return(new_node->id);
				}//if
			else{
				while(curr->next != NULL) curr  = curr->next;
				curr->next = new_node;
				new_node->prev = curr;
				return(new_node->id);
				}//else
		}//func

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///// Получение эффекта по имени
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	ID3DXEffect* GetEffect(CRLEngi_string   Name,D3DXMATRIX* view,D3DXMATRIX* proj){
		
		NODE_PTR curr = NULL;
        curr = head;
		D3DXVECTOR4 pos;
		pos.x =Camera_Manager->CurrientCamera->Camera->Position.x;
		pos.y =Camera_Manager->CurrientCamera->Camera->Position.x;
		pos.z =Camera_Manager->CurrientCamera->Camera->Position.x;
		pos.w = 1.0f;
		(*view) = Camera_Manager->CurrientCamera->Camera->CamView;
		(*proj) = Camera_Manager->CurrientCamera->Camera->CamProjection;

		while (true){
			
			curr->Effect->SetVector( "View_Pos",   &(pos));

            if (curr->Name == Name)
				return (curr->Effect);
			if(curr->next == NULL) break;
			curr = curr->next;
		 }
		return NULL;	
	}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//#################################################################################################################
public:
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                     КОНСТРУКТОР
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	CLREngi_Effect_Manager(LPDIRECT3DDEVICE9       Device,
		                   CLREngi_Camera_Manager *Cam_Manager,
		                   CLREngi_Console   *Cnsl){ 
		g_pd3dDevice= Device;
		LOADED_Effects = 0;
		head = NULL;
		Console = Cnsl ;
		Camera_Manager = Cam_Manager;
	};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                       ДЕСТРУКТОР
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual ~CLREngi_Effect_Manager(){
	};
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#endif 
